package top.starshine.pack;

import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.regex.Pattern;

public final class JsonSerializableSupport {
    public static final char COMMA = ',';
    public static final char QUOTE = '"';
    public static final char COLON = ':';
    public static final String NULL_CHAR = null;
    private static final Pattern JSON_STRING_STARTER_END = Pattern.compile("^\\{.*}$|^\\[.*]$");// {},[]
    //public static Supplier<StringBuilder> stringBuilderSupplier;
    static SystemStringBuilderPool systemStringBuilderPool;// 对象缓存池

    public static void parse (
            StringBuilder sb,
            Object obj
    ) {
        // 空值
        if (null == obj) {
            sb.append(NULL_CHAR);
        }
        // 字符串
        else if (obj instanceof String) {
            String str = (String) obj;
            // 空值不处理
            if (StringUtils.isBlank(str)) {
                sb.append(NULL_CHAR);
            } else {
                char[] chars = str.toCharArray();
                sb.ensureCapacity(chars.length + 2);
                sb.append(QUOTE);
                for (char c : chars) {
                    if (c == QUOTE) {
                        sb.append('\\');
                    }
                    sb.append(c);
                }
                sb.append(QUOTE);
            }
        }
        // 处理有实现的
        else if (obj instanceof JsonSerializable) {
            // 判断是不是有缓存
//            if (cacheStringBuilderEmpty()) {
//                sb.append(((JsonSerializable) obj).toJson());
//            } else {
//                StringBuilder stringBuilder = ((JsonSerializable) obj).genJsonBody();
//                if (!(sb == stringBuilder)) {
//                    sb.append(stringBuilder);
//                }
//                sb.append('}');
//            }
            sb.append(((JsonSerializable) obj).toJson());
        }
        // 处理 map
        else if (obj instanceof Map) {
            if (((Map<?, ?>) obj).isEmpty()) {
                sb.ensureCapacity(2);
                sb.append('{').append('}');
            } else {
                sb.append('{');
                Character comma = null;
                boolean flag = false;
                for (Map.Entry<?, ?> entry : ((Map<?, ?>) obj).entrySet()) {
                    Object value = entry.getValue();
                    if (flag) {
                        sb.append(COMMA);
                    } else {
                        flag = true;
                    }
                    sb.append(QUOTE).append(entry.getKey()).append(QUOTE).append(COLON);
                    parse(sb, value);
                }
                sb.append('}');
            }
        }
        // 处理 Iterable，支持迭代器
        else if (obj instanceof Iterable) {
            sb.append('[');
            boolean flag = false;
            for (Object oneMate : (Iterable<?>) obj) {
                if (flag) {
                    sb.append(COMMA);
                } else {
                    flag = true;
                }
                parse(sb, oneMate);
            }
            sb.append(']');
        }
        // 处理 jdk8 时间
        else if (obj instanceof LocalDateTime) {
            sb.append('"');
            LocalDateTime localDateTime = (LocalDateTime) obj;// yyyy-MM-dd HH:mm:ss.SSS
            sb.append(localDateTime.toLocalDate().toString());
            sb.append(' ');
            sb.append(DatePattern.NORM_TIME_FORMATTER.format((localDateTime.toLocalTime())));// 格式 HH:mm:ss
            sb.append('"');
        }
        // 处理 jdk8 时间
        else if (obj instanceof LocalTime) {
            sb.append('"');
            sb.append(DatePattern.NORM_TIME_FORMATTER.format((LocalTime) obj));// 格式 HH:mm:ss
            sb.append('"');
        } else if (obj instanceof LocalDate) {
            sb.append('"');
            sb.append(obj);// jdk8 时间都走 toString >>> yyyy-MM-dd
            sb.append('"');
        }
        // 处理 jdk默认 时间
        else if (obj instanceof Date) {
            sb.append(DatePattern.NORM_DATETIME_FORMAT.format((Date) obj));
        }
        // 其他类型
        else {
            sb.append(JSONObject.toJSONString(obj));// 无法识别的都走 json 序列化
        }
    }

    public static String parse (Object obj) {
        StringBuilder sb = systemStringBuilderPool.borrow();
        try {
            parse(sb, obj);
            return sb.toString();
        } finally {
            systemStringBuilderPool.retrieve(sb);
        }
    }

    public static String stringSerializable (String str) {
        // 空值不处理
        if (StringUtils.isBlank(str)) {
            return str;
        }
        // 针对 json 字符串特殊处理
        else if (JSON_STRING_STARTER_END.matcher(str).matches()) {
            return str.replaceAll("\"", "\\\\\"");
        }
        // 默认处理
        else {
            return str.contains("\"") ? str.replaceAll("\"", "\\\\\"") : str;
        }
    }

    private static boolean isQuote (Object value) {
        if (null == value)
            return false;
        else if (value instanceof String)
            return true;
        else if (value instanceof LocalDateTime)
            return true;
        else if (value instanceof LocalDate)
            return true;
        else if (value instanceof Date)
            return true;
        else return (value instanceof LocalTime);
    }

//    public static StringBuilder getCacheStringBuilder () {
//        // 获取缓存
//        if (null == stringBuilderSupplier) {
//            return new StringBuilder();
//        } else {
//            return stringBuilderSupplier.get();
//        }
//    }
//
//    public static StringBuilder cacheStringBuilder () {
//        // 获取缓存
//        StringBuilder stringBuilder;
//        if (null == stringBuilderSupplier) {
//            stringBuilder = new StringBuilder();
//        } else {
//            stringBuilder = stringBuilderSupplier.get();
//        }
//        if (stringBuilder.length() > 0) {
//            stringBuilder.setLength(0);
//        }
//        return stringBuilder;
//    }

    public static <T> String cacheJoin (
            T character,
            Object... args
    ) {
        if (args.length == 0) {
            return "";
        }
        // 获取缓存
        StringBuilder sb = systemStringBuilderPool.borrow();
        try {
            boolean flag = false;
            for (Object arg : args) {
                if (flag) {
                    sb.append(character);
                } else {
                    flag = true;
                }
                sb.append(arg);
            }
            return sb.toString();
        } finally {
            systemStringBuilderPool.retrieve(sb);
        }
    }

    public static String cacheAppend (Object... args) {
        if (args.length == 0) {
            return "";
        }
        // 获取缓存
        StringBuilder sb = systemStringBuilderPool.borrow();
        try {
            for (Object arg : args) {
                sb.append(arg);
            }
            return sb.toString();
        } finally {
            systemStringBuilderPool.retrieve(sb);
        }
    }

//    public static boolean cacheStringBuilderEmpty () {
//        // 获取缓存
//        return null == stringBuilderSupplier || null == stringBuilderSupplier.get();
//    }

    private JsonSerializableSupport () {
    }

//    public static void resetCacheStringBuilder () {
//        if (null != stringBuilderSupplier) {
//            StringBuilder sb = stringBuilderSupplier.get();
//            if (null != sb && sb.length() > 0) {
//                sb.setLength(0);
//            }
//        }
//    }

    public static boolean hasBaseClass (Object arg) {
        return arg instanceof JsonSerializable
                || arg instanceof String
                || arg instanceof String[]
                || arg instanceof Long
                || arg instanceof Long[]
                || arg instanceof Integer
                || arg instanceof Integer[]
                || arg instanceof BigDecimal
                || arg instanceof BigDecimal[]
                || arg instanceof Short
                || arg instanceof Short[]
                || arg instanceof Byte
                || arg instanceof Byte[]
                || arg instanceof LocalDateTime
                || arg instanceof LocalDateTime[]
                || arg instanceof LocalDate
                || arg instanceof LocalDate[]
                || arg instanceof LocalTime
                || arg instanceof LocalTime[];
    }

    public static void registered (SystemStringBuilderPoolProperties properties) {
        if (null == properties) {
            properties = new SystemStringBuilderPoolProperties();
        }
        synchronized (SystemStringBuilderPoolProperties.class) {
            // 是否存在旧的，先关闭旧的
            if (null != JsonSerializableSupport.systemStringBuilderPool) {
                JsonSerializableSupport.systemStringBuilderPool.shutdown();
            }
            // 执行创建新的
            JsonSerializableSupport.systemStringBuilderPool = new SystemStringBuilderPool(properties);
        }
    }

    public static StringBuilder borrow () {
        return systemStringBuilderPool.borrow();
    }

    public static void retrieve (StringBuilder sb) {
        systemStringBuilderPool.retrieve(sb);
    }

    public static void shutdown () {
        systemStringBuilderPool.shutdown();
    }

    public static String append (Object... args) {
        if (args.length == 0) {
            return "";
        }
        // 获取缓存
        StringBuilder sb = systemStringBuilderPool.borrow();
        try {
            for (Object arg : args) {
                sb.append(arg);
            }
            return sb.toString();
        } finally {
            systemStringBuilderPool.retrieve(sb);
        }
    }

    public static void appends (Consumer<StringBuilder> consumer) {
        // 获取缓存
        StringBuilder sb = systemStringBuilderPool.borrow();
        try {
            consumer.accept(sb);
        } finally {
            systemStringBuilderPool.retrieve(sb);
        }
    }

//    /** 是否有缓存池 */
//    public static boolean hasPool () {
//        return stringBuilderSupplier != null;
//    }

}